#include "FIMsgProcess.h"

#include <core/Utility.h>
#include <qbkernel/include/qb_base.h>
#include <qbprotocol/include/MessageParserTool.h>
#include <qbprotocol/include/SSFIModel.h>
#include <qbprotocol/include/SSGMktModel.h>
#include <qbprotocol/include/SSQBAModel.h>
#include <qbprotocol/include/rdProto.h>

using namespace qb;

namespace {
#define Reg_Func(ID)                               \
  qbBase::getMessageBond()->RegisterDecodeFunc(ID, \
                                               qbmsg::fixedincome::ExtracFunc)
#define DelPtr(FUNC, TYPE)               \
  case FUNC: {                           \
    TYPE* p = static_cast<TYPE*>(toDel); \
    delete p;                            \
    return nullptr;                      \
  } break;

void* delAck(int func, void* toDel) {
  switch (func) {
    DelPtr(E_FID_QBA_PUBLIC_OPTION_V2_REQ, xQBAPublicOptionListV2_c);
    DelPtr(E_FID_QBA_PUBLIC_OPTION_V2_PUSH, xQBAPublicOptionListV2_c);
    DelPtr(E_FID_CIB_REPO_REQ, xQbCibRepoAck_c);
    DelPtr(E_FID_CIB_REPO_PUSH, xQbCibRepoAck_c);
    DelPtr(E_FID_QB_FIXIN_REPO_RATE_QUERY, xShiborList_c);
    DelPtr(E_FID_QB_FIXIN_REPO_RATE_PUSH, xShiborList_c);
    DelPtr(E_FID_QB_FIXIN_DEPO_REPO_RATE_QUERY, xShiborList_c);
    DelPtr(E_FID_QB_FIXIN_DEPO_REPO_RATE_PUSH, xShiborList_c);
    DelPtr(E_FID_QB_SHIBOR_QUERY, xShiborList_c);
    DelPtr(E_FID_QB_SHIBOR_PUSH, xShiborList_c);
    DelPtr(E_FID_QBA_PUBLIC_OPTION_SETTING_QRY_V2, xQBAPubOptSettingV2Req);
    DelPtr(E_FID_QBA_PUBLIC_OPTION_SETTING_ADD_V2, xQBAPubOperSettingAddV2Req);
    DelPtr(E_FID_QB_BATCH_GMKT_INDEX_PRICE_REQ,
           xBatchGMktIndexPriceAck_c);  // xBatchGMktIndexPriceReq_c
    DelPtr(E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_PUSH,
           xGMktIndexPriceUpDownAck_c);  // xGMktIndexPriceUpDownReq_c
    // DelPtr(E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_CANCEL,
    // xGMktIndexPriceUpDownReq_c); -- no response
    DelPtr(E_FID_QBA_CNEX_INDEX_REQ, xQBACNEXList_c);
    DelPtr(E_FID_QBA_CNEX_INDEX_PUSH, xQBACNEXList_c);
      // DelPtr(E_FID_QBA_CNEX_INDEX_PUSH_CANCEL, ); -- no response

    default:
      break;
  }
  return toDel;
}
}  // namespace

void qbmsg::fixedincome::InitDecodeFuncs() {
  Reg_Func(E_FID_QBA_PUBLIC_OPTION_V2_REQ);
  Reg_Func(E_FID_QBA_PUBLIC_OPTION_V2_PUSH);
  Reg_Func(E_FID_CIB_REPO_REQ);
  Reg_Func(E_FID_CIB_REPO_PUSH);
  Reg_Func(E_FID_QB_FIXIN_REPO_RATE_QUERY);
  Reg_Func(E_FID_QB_FIXIN_REPO_RATE_PUSH);
  Reg_Func(E_FID_QB_FIXIN_DEPO_REPO_RATE_QUERY);
  Reg_Func(E_FID_QB_FIXIN_DEPO_REPO_RATE_PUSH);
  Reg_Func(E_FID_QB_SHIBOR_QUERY);
  Reg_Func(E_FID_QB_SHIBOR_PUSH);
  Reg_Func(E_FID_QBA_PUBLIC_OPTION_SETTING_QRY_V2);
  Reg_Func(E_FID_QBA_PUBLIC_OPTION_SETTING_ADD_V2);
  Reg_Func(E_FID_QB_BATCH_GMKT_INDEX_PRICE_REQ);
  Reg_Func(E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_PUSH);
  Reg_Func(E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_CANCEL);
  Reg_Func(E_FID_QBA_CNEX_INDEX_REQ);
  Reg_Func(E_FID_QBA_CNEX_INDEX_PUSH);
  Reg_Func(E_FID_QBA_CNEX_INDEX_PUSH_CANCEL);
}

void qbmsg::fixedincome::EncodeFunc(qb::proto::Message& msg,
                                    qb::SSRequestMsg* req) {
  switch (req->m_FuncID) {
    case E_FID_QBA_PUBLIC_OPTION_V2_REQ:
    case E_FID_QBA_PUBLIC_OPTION_V2_PUSH: {
      const QBAPublicOptionReq* pdata = (QBAPublicOptionReq*)req->m_pRequest;
      qb::proto::VariantMap submsg;
      submsg.setUint32("beginDate", pdata->m_beginDate);
      submsg.setUint32("endDate", pdata->m_endDate);
      msg.SetMap("xQBAPublicOptionReq", submsg);
      break;
    }
    case E_FID_CIB_REPO_REQ:  // = 50828,
                              // //请求，银行间回购请求
    {
      const xQbCibRepoReq_c* pdata = (xQbCibRepoReq_c*)req->m_pRequest;

      qb::proto::VariantMap submsg;
      submsg.SetInt32("Date", pdata->m_Date);
      msg.SetMap("xQbCibRepoReq", submsg);
      break;
    }
    case E_FID_QBA_PUBLIC_OPTION_SETTING_QRY_V2:  // = 50407,
                                                  // // 固收综合屏
                                                  // 公开市场操作-净投放计算公式查询
    {
      xQBAPubOptSettingV2Req* pReq = (xQBAPubOptSettingV2Req*)req->m_pRequest;

      qb::proto::VariantMap submsg;
      submsg.setString("UserId", pReq->m_UserId);

      msg.SetMap("xQBAPubOptSettingV2Req", submsg);

      break;
    }
    case E_FID_QBA_PUBLIC_OPTION_SETTING_ADD_V2:  // = 50408,
                                                  // // 固收综合屏
                                                  // 公开市场操作-净投放计算公式保存
    {
      xQBAPubOperSettingAddV2Req* pReq =
          (xQBAPubOperSettingAddV2Req*)req->m_pRequest;

      qb::proto::VariantMap submsg;
      submsg.setString("UserId", pReq->m_UserId);
      submsg.setString("Select", pReq->m_Select);
      submsg.SetUInt32("InitFlag", pReq->m_nInitFlag);
      msg.SetMap("xQBAPubOperSettingAddV2Req", submsg);

      break;
    }
    case E_FID_QB_BATCH_GMKT_INDEX_PRICE_REQ:  // = 53320 批量指标价格请求
    {
      xBatchGMktIndexPriceReq_c* pReq =
          (xBatchGMktIndexPriceReq_c*)req->m_pRequest;
      qb::proto::VariantMap submsg;
      submsg.setString("UserId", pReq->m_UserId);
      submsg.setString("CompanyId", pReq->m_CompanyId);
      qb::proto::VariantList indexes;
      for (const auto& index : pReq->m_Indexes) {
        indexes.push_back(index);
      }
      submsg.setList("Indexes", indexes);
      msg.SetMap("xBatchGMktIndexPriceReq", submsg);
      break;
    }
    case E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_PUSH:
    case E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_CANCEL: {
      xGMktIndexPriceUpDownReq_c* pReq =
          (xGMktIndexPriceUpDownReq_c*)req->m_pRequest;
      qb::proto::VariantMap submsg;
      submsg.setString("UserId", pReq->m_UserId);
      submsg.setString("CompanyId", pReq->m_CompanyId);
      submsg.setString("IndexId", pReq->m_IndexId);
      msg.SetMap("xGMktIndexPriceUpDownReq_c", submsg);
    } break;
    case E_FID_QBA_CNEX_INDEX_REQ:
    case E_FID_QBA_CNEX_INDEX_PUSH:
    case E_FID_QBA_CNEX_INDEX_PUSH_CANCEL: {
    } break;
    case E_FID_QB_FIXIN_REPO_RATE_QUERY:  // 50221, 回购定盘查询，无请求包体
    case E_FID_QB_FIXIN_REPO_RATE_PUSH:  // 50388,	回购定盘推送，无请求包体
    case E_FID_QB_FIXIN_DEPO_REPO_RATE_QUERY:  // 50287,
                                               // 银银间回购定盘查询，无请求包体
    case E_FID_QB_FIXIN_DEPO_REPO_RATE_PUSH:  // 50400,
                                              // 银银间回购定盘推送，无请求包体
    case E_FID_QB_SHIBOR_QUERY:  // 50220, Shibor查询，无请求包体
    case E_FID_QB_SHIBOR_PUSH:   // 50832, Shibor推送，无请求包体
    default:
      break;
  }
}

void* qbmsg::fixedincome::ExtracFunc(int func, const ProtoMessage& msg,
                                     void* toDel) {
  if (toDel != nullptr) return delAck(func, toDel);

  switch (func) {
    case E_FID_QBA_PUBLIC_OPTION_V2_REQ:
    case E_FID_QBA_PUBLIC_OPTION_V2_PUSH: {
      xQBAPublicOptionListV2_c* ptr = new xQBAPublicOptionListV2_c;
      if (!ptr) return nullptr;

      ProtoList msglist;
      if (msg.getList("List", msglist)) {
        xQBAPublicOptionUnit_c xUnit;
        for (const auto& it : msglist) {
          if (it.Type != ProtoValue::VAR_MAP) continue;
          const ProtoMap& msgmap = it;

          memset(&xUnit, 0, sizeof(xQBAPublicOptionUnit_c));
          msgmap.getUint32("Date", xUnit.m_Date);
          FIELDCOPY(xUnit.m_Type, CParserTool::GetString(msgmap, "Type"));
          FIELDCOPY(xUnit.m_Type_En, CParserTool::GetString(msgmap, "Type_En"));
          FIELDCOPY(xUnit.m_TermType,
                    CParserTool::GetString(msgmap, "TermType"));
          FIELDCOPY(xUnit.m_TermType_En,
                    CParserTool::GetString(msgmap, "TermType_En"));
          if (!msgmap.GetDouble("Rate", xUnit.m_Rate)) xUnit.m_Rate = 1e-18f;
          if (!msgmap.GetDouble("Money", xUnit.m_Money)) xUnit.m_Money = 1e-18f;

          ptr->m_List.push_back(xUnit);
        }
      }
      msglist.clear();
      if (msg.getList("DelList", msglist)) {
        xQBAPublicOptionUnit_c xUnit;
        for (const auto& it : msglist) {
          if (it.Type != ProtoValue::VAR_MAP) continue;
          const ProtoMap& msgmap = it;

          memset(&xUnit, 0, sizeof(xQBAPublicOptionUnit_c));
          msgmap.getUint32("Date", xUnit.m_Date);
          FIELDCOPY(xUnit.m_Type, CParserTool::GetString(msgmap, "Type"));
          FIELDCOPY(xUnit.m_Type_En, CParserTool::GetString(msgmap, "Type_En"));
          FIELDCOPY(xUnit.m_TermType,
                    CParserTool::GetString(msgmap, "TermType"));
          FIELDCOPY(xUnit.m_TermType_En,
                    CParserTool::GetString(msgmap, "TermType_En"));
          if (!msgmap.GetDouble("Rate", xUnit.m_Rate)) xUnit.m_Rate = 1e-18f;
          if (!msgmap.GetDouble("Money", xUnit.m_Money)) xUnit.m_Money = 1e-18f;

          ptr->m_DelList.push_back(xUnit);
        }
      }
      msglist.clear();
      if (msg.getList("NetInvList", msglist)) {
        for (const auto& it : msglist) {
          if (it.Type != ProtoValue::VAR_MAP) continue;
          const ProtoMap& msgmap = it;

          QBAPubOptNetInvFactor inv;
          msgmap.GetInt32("id", inv.id);
          msgmap.GetInt32("order", inv.order);
          msgmap.GetInt32("default", inv.dft);
          msgmap.GetDouble("value", inv.value);
          msgmap.GetDouble("weekValue", inv.weekValue);
          msgmap.GetDouble("monthValue", inv.monthValue);
          inv.name = CParserTool::GetString(msgmap, "name");
          inv.name_en = CParserTool::GetString(msgmap, "name_en");
          ptr->m_NetInvList.push_back(inv);
        }
      }
      return ptr;
      break;
    }
    case E_FID_CIB_REPO_REQ: {
      ProtoList AckList;
      if (!msg.GetList("List", AckList)) return nullptr;

      xQbCibRepoAck_c* ptr = new xQbCibRepoAck_c;
      if (!ptr) return nullptr;

      for (const auto& it : AckList) {
        if (it.Type != ProtoValue::VAR_MAP) continue;
        const ProtoMap& ibMap = it;

        xQbCibRepo_c ibRepo;
        FIELDCOPY(ibRepo.m_szID, CParserTool::GetString(ibMap, "ID"));
        ibMap.GetDouble("Rate", ibRepo.m_dRate);
        ibMap.GetDouble("Diff", ibRepo.m_dDiff);
        CParserTool::MessageGetTime(ibMap, "UpdateTime", ibRepo.m_tUpdateTime);
        ptr->m_List.push_back(ibRepo);
      }
      return ptr;
      break;
    }
    case E_FID_QB_FIXIN_REPO_RATE_QUERY:       // 50221, 回购定盘查询
    case E_FID_QB_FIXIN_REPO_RATE_PUSH:        // 50388,	回购定盘推送
    case E_FID_QB_FIXIN_DEPO_REPO_RATE_QUERY:  // 50287, 银银间回购定盘查询
    case E_FID_QB_FIXIN_DEPO_REPO_RATE_PUSH:  // 50400, 银银间回购定盘推送
    case E_FID_QB_SHIBOR_QUERY:               // 50220, Shibor查询
    case E_FID_QB_SHIBOR_PUSH:                // 50832, Shibor推送
    {
      ProtoList msglist;
      if (!msg.getList("list", msglist)) return nullptr;

      xShiborList_c* ptr = new xShiborList_c;
      if (!ptr) return nullptr;

      for (const auto& it : msglist) {
        if (it.Type != ProtoValue::VAR_MAP) continue;
        xBaseUnit_c unit;

        const ProtoMap& msgmap = it;

        FIELDCOPY(unit.m_term, CParserTool::GetString(msgmap, "term"));
        FIELDCOPY(unit.m_gjk_code, CParserTool::GetString(msgmap, "gjk_code"));
        msgmap.GetDouble("rate", unit.m_rate);      // 税后净值变动
        msgmap.GetDouble("change", unit.m_change);  // 税后利息收入
        msgmap.GetUInt32("date", unit.m_date);
        ptr->m_List.push_back(unit);
      }
      ptr->m_List.sort();
      return ptr;
      break;
    }
    case E_FID_QBA_PUBLIC_OPTION_SETTING_ADD_V2:
    case E_FID_QBA_PUBLIC_OPTION_SETTING_QRY_V2: {
      xQBAPubOptSettingV2Ack* ptr = new xQBAPubOptSettingV2Ack;
      if (!ptr) return nullptr;
      FIELDCOPY(ptr->m_UserId, CParserTool::GetString(msg, "UserID"));
      msg.GetUInt32("InitFlag", ptr->m_nInitFlag);
      FIELDCOPY(ptr->m_Select, CParserTool::GetString(msg, "Select"));
      return ptr;
    } break;

    case E_FID_QB_BATCH_GMKT_INDEX_PRICE_REQ:  // 53320, //批量指标价格
    {
      ProtoList msglist;
      if (!msg.getList("IndexList", msglist)) return nullptr;

      xBatchGMktIndexPriceAck_c* ptr = new xBatchGMktIndexPriceAck_c;
      if (!ptr) return nullptr;

      xGMktIndexPriceUpDownUnit_c unit;
      for (const auto& it : msglist) {
        if (it.Type != ProtoValue::VAR_MAP) continue;
        const ProtoMap& msgmap = it;

        FIELDCOPY(unit.m_IndexId, CParserTool::GetString(msgmap, "IndexId"));
        FIELDCOPY(unit.m_Price, CParserTool::GetString(msgmap, "Price"));
        FIELDCOPY(unit.m_UpDownPercent,
                  CParserTool::GetString(msgmap, "UpDownPercent"));
        FIELDCOPY(unit.m_UpDownPoint,
                  CParserTool::GetString(msgmap, "UpDownPoint"));

        int time = 0;
        msgmap.getInt32("DateTime", time);
        unit.m_DateTime = time;

        // version :
        int iversion = 0;
        msgmap.getInt32("Version", iversion);
        unit.m_Version = iversion;

        ptr->m_IndexList.push_back(unit);
      }

      return ptr;
    } break;
    case E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_PUSH:
    case E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_CANCEL: {
      xGMktIndexPriceUpDownAck_c* ptr = new xGMktIndexPriceUpDownAck_c;

      FIELDCOPY(ptr->m_IndexId, CParserTool::GetString(msg, "IndexId"));
      FIELDCOPY(ptr->m_Price, CParserTool::GetString(msg, "Price"));
      FIELDCOPY(ptr->m_UpDownPercent,
                CParserTool::GetString(msg, "UpDownPercent"));
      FIELDCOPY(ptr->m_UpDownPoint, CParserTool::GetString(msg, "UpDownPoint"));

      // 时间 :
      int ttime = 0;
      msg.GetInt32("DateTime", ttime);
      ptr->m_DateTime = ttime;

      // Ver
      msg.GetInt32("Version", ptr->m_Version);
      return ptr;
    } break;
    case E_FID_QBA_CNEX_INDEX_REQ:
    case E_FID_QBA_CNEX_INDEX_PUSH: {
      xQBACNEXList_c* ptr = new xQBACNEXList_c;
      msg.GetInt32("countPerDay", ptr->m_countPerDay);

      ProtoList msglist;
      if (!msg.getList("List", msglist)) return ptr;

      xQBACNEXUnit_c xUnit;
      for (const auto& it : msglist) {
        if (it.Type != ProtoValue::VAR_MAP) continue;
        const ProtoMap& msgmap = it;
        msgmap.GetInt32("Index", xUnit.m_index);
        FIELDCOPY(xUnit.m_CNEXTimeNode,
                  CParserTool::GetString(msgmap, "CNEXTimeNode"));

        if (!msgmap.GetFloat("CNEXAllMarket", xUnit.m_CNEXAllMarket))
          xUnit.m_CNEXAllMarket = 1e-18f;
        if (!msgmap.GetFloat("CNEXAllBank", xUnit.m_CNEXAllBank))
          xUnit.m_CNEXAllBank = 1e-18f;
        if (!msgmap.GetFloat("CNEXSmallBank", xUnit.m_CNEXSmallBank))
          xUnit.m_CNEXSmallBank = 1e-18f;
        if (!msgmap.GetFloat("CNEXNotBank", xUnit.m_CNEXNotBank))
          xUnit.m_CNEXNotBank = 1e-18f;
        CParserTool::MessageGetInt64toTime(msgmap, "CNEXTime",
                                           xUnit.m_CNEXTime);

        ptr->m_CNEXList.push_back(xUnit);
      }
      return ptr;
    } break;
    case E_FID_QBA_CNEX_INDEX_PUSH_CANCEL: {
    } break;
    default:
      break;
  }

  return nullptr;
}
